/**
 * This file is part of decent-cpp.
 *
 * decent-cpp is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * decent-cpp is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with decent-cpp.  If not, see <http://www.gnu.org/licenses/>.
 */

// clang-format off
#include <stdio.h>
// clang-format on
#include <readline/history.h>
#include <readline/readline.h>
#include <sodium.h>
#include <sqlite3.h>
//#include <boost/log/trivial.hpp>
//#include <boost/log/utility/setup.hpp>
//#include <nlohmann/json.hpp>
//#include <server_ws.hpp>
#include "util.h"
#include "http.h"
#include "data.h"
#include "ws.h"

// using WsServer = SimpleWeb::SocketServer<SimpleWeb::WS>;

static void init_log() {
/*  static const std::string COMMON_FMT(
      "[%TimeStamp%][%ThreadID%][%Severity%]:  %Message%");

  boost::log::register_simple_formatter_factory<
      boost::log::trivial::severity_level, char>("Severity");

  // Output message to console
  boost::log::add_console_log(std::cout,
                              boost::log::keywords::format = COMMON_FMT,
                              boost::log::keywords::auto_flush = true);

  boost::log::add_common_attributes();

  // Only output message with INFO or higher severity in Release
#ifndef DEBUG
  boost::log::core::get()->set_filter(boost::log::trivial::severity >=
                                      boost::log::trivial::info);
#endif
*/}

int main(/*int argc, char** argv*/) {
  // WsServer server;
  // server.config.port = 13337;

  if (sodium_init() < 0) {
    return -1;
  }

  init_log();

  // Output some simple log message
  /*BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
  BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
  BOOST_LOG_TRIVIAL(info) << "An informational severity message";
  BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
  BOOST_LOG_TRIVIAL(error) << "An error severity message";
  BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
#ifdef DEBUG
  BOOST_LOG_TRIVIAL(info) << "Running in debug mode";
#endif
*/
  printf("Decent version: %s/%s\n", dc::version_impl().c_str(),
         dc::version_api().c_str());
  printf("Sodium version: %s\n", sodium_version_string());
  printf("Sqlite3 version: %s\n", sqlite3_version);
  try {
    dc::data_init();
    dc::server_http_init();
  } catch (std::runtime_error& e) {
    printf("Error during init: %s\n", e.what());
    return -1;
  } catch (std::exception& e) {
    printf("Error during init: %s\n", e.what());
    return -1;
  } catch (...) {
    printf("Error during init: unknown\n");
    return -1;
  }

  printf("Welcome! You can exit by pressing Ctrl+C at any time...\n");

  char* buf;
  while ((buf = readline(">> ")) != nullptr) {
    if (strlen(buf) > 0) {
      add_history(buf);
    }

    printf("[%s]\n", buf);

    if (strcmp(buf, "quit") == 0) {
      free(buf);
      break;
    }

    std::string cmd = buf;
    if (cmd.find("sets ") == 0) {
      std::string params = cmd.substr(5);
      printf("Params %s\n", params.c_str());
      size_t spaceIdx = params.find(' ');
      if (spaceIdx == std::string::npos) {
        printf("Invalid sets command\n");
      } else {
        std::string name = params.substr(0, spaceIdx);
        std::string value = params.substr(spaceIdx + 1);
        printf("Name %s value %s\n", name.c_str(), value.c_str());
        try {
          nlohmann::json json = nlohmann::json::parse(value);
          printf("Setting %s to %s\n", name.c_str(), json.dump().c_str());
          dc::data_setting_set(name, json);
          printf("Done\n");
        } catch (std::exception& e) {
          printf("JSON error: %s\n", e.what());
        }
      }
    } else if (cmd.find("hash ") == 0) {
      std::string pwd = cmd.substr(5);
      std::string hash = dc::pwd_hash(pwd);
      printf("meme: %s\n", hash.c_str());
    }

    // readline malloc's a new buffer every time.
    free(buf);
  }

  dc::server_http_kill();
  dc::data_close();
  return 0;
}
